package com.learn.im.websocket;

import com.alibaba.fastjson.JSON;
import com.learn.im.domain.Chat;
import com.learn.im.domain.FileMessage;
import com.learn.im.enums.ChatType;
import com.learn.im.enums.MsgType;
import com.learn.im.factory.MessageHandlerContext;
import com.learn.im.servcie.IChatFileTranf;
import com.learn.im.servcie.MessageHandler;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.*;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Emp
 * @version :    1.0
 */
@Data
@Slf4j
@Component
@ServerEndpoint(value = "/im/ws/{sid}")
public class IMServer {
    // 会话池
    private static final Map<String,IMServer> clients = new ConcurrentHashMap<>();

    private String username;

    private Session session;

    private FileMessage fileInstance;

    private static MessageHandlerContext context;
    private static IChatFileTranf chatFileTranf;

    @Autowired
    public void setMessageHandlerContext(MessageHandlerContext messageHandlerContext) {context = messageHandlerContext;}
    @Autowired
    public void IChatFileTranf(IChatFileTranf tranf) { chatFileTranf = tranf; }
    /**
     * 建立连接
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "sid") String username) throws UnsupportedEncodingException {
        this.username = URLDecoder.decode(username, "UTF-8");
        this.session = session;
        clients.put(this.username,this);
        // 发送上线消息
        Chat up = Chat.builder().from("system").to("*").content(username).chatType(ChatType.UP.name()).build();
        broadcast(up);

        log.info("[{}]建立连接,当前在线人数:{}",this.username,onlineNum());
    }

    /**
     * 接收消息
     */
    @OnMessage
    public void onMessage(String message,Session session){
        Chat chat = JSON.parseObject(message, Chat.class);
        chat.setTime(new Date());
        // 聊天类型
        ChatType type = ChatType.valueOf(chat.getChatType());
        switch (type){
            case FANOUT:
                broadcast(chat);
                break;
            case NORMAL:
                MsgType msgType = MsgType.valueOf(chat.getMsgType());
                MessageHandler handler = context.createHandler(msgType);
                handler.handle(chat,this);
                break;
            default:
                log.error("暂不支持{}类型消息",type.name());
        }
    }

    /**
     * 接收二进制数据
     */
    @OnMessage
    public void onMessage(ByteBuffer buffer, Session session) throws IOException {
        if (chatFileTranf.saveFile(fileInstance, buffer.array())) {
            // 分片保存成功响应next让客户端继续下一分片
            command("next");
        } else {
            command("resend");
        }
    }

    /**
     * 关闭连接
     */
    @OnClose
    public void onClose(Session session){
        clients.remove(this.username);
        log.info("[{}]关闭连接,当前在线人数:{}",this.username,onlineNum());
        // 发送下线消息
        Chat down = Chat.builder().from("system").to("*").content(username).chatType(ChatType.DOWN.name()).build();
        broadcast(down);
    }

    /**
     * 发生错误
     */
    @OnError
    public void onError(Session session,Throwable t){
        clients.remove(this.username);
        log.error("[{}]连接发生错误,原因:{}",this.username,t.getMessage());
    }

    /**
     * 广播消息
     */
    public void broadcast(Chat chat){
        for (IMServer value : clients.values()) {
            try {
                value.session.getBasicRemote().sendText(JSON.toJSONString(chat));
            } catch (Exception e) {
                log.error("{}广播失败,原因:{}",value.username,e.getMessage());
            }
        }
    }

    /**
     * 发送简短命令
     */
    public void command(String command) throws IOException {
        this.session.getBasicRemote().sendText(command);
    }

    /**
     * 发送文件消息
     */
    public boolean sendFile(){
        IMServer imServer = clients.get(fileInstance.getChat().getTo());
        return chatFileTranf.sendFile(fileInstance.getType(), imServer.session, fileInstance);
    }

    /**
     * 发送图片消息
     */
    public boolean sendPic(){
        IMServer imServer = clients.get(fileInstance.getChat().getTo());
        return chatFileTranf.handleImg(imServer.session, fileInstance);
    }

    /**
     * 在线用户
     */
    public Collection<String> onlineUser(){
        return clients.keySet();
    }

    /**
     * 在线人数
     */
    public long onlineNum(){
        return clients.size();
    }

    /**
     * 通过用户名获取连接实例
     */
    public IMServer client(String username){
        return clients.get(username);
    }
}
